<?php

/***  DOCUMENTATION LAYER

CEO Output Class

Name: CeoOutput
Last Update: Sep 2007
Author: Tom at klenwell@gmail.com

DESCRIPTION
  Briefly describe class here

METHODS
  MAGIC
  CeoOutput($debug=0, $oid=null)    *php 4 constructor*
  __construct($debug, $oid)          *php 5 constructor*
  __destruct()  
  
  PUBLIC
  print_d($message, $color='c33')
  print_r()
  dump()
  
  PRIVATE
  _set_session_data()
  _get_session_data()
  _has_session_data()
  _set_filename()
  _set_dirpath()
  
USAGE
  $Class = new ClassClass();
  $Class->print_r('hello world']);

NOTES
  
______________________________________________________________________________*/

// Load File of Base Class
$base_fname = 'class.abstract.php';
$base_dirpath = dirname(__FILE__) . DIRECTORY_SEPARATOR;
#require_once($base_dirpath . $base_fname);


// Class
/*____________________________________________________________________________*/
class CeoOutput
{
/* PUBLIC PROPERTIES */
var $debug = 0;
var $class_name = __CLASS__;
var $oid = '';
var $DS = DIRECTORY_SEPARATOR;

// arrays
var $PANEL = array();
var $HEAD = array();
var $HTML = array();
var $REQ_HEAD = array();
var $DEFAULT = array();

// vars

/* PRIVATE PROPERTIES */
var $_filename = '';
var $_dirpath = '';


/* ** MAGIC METHODS ** */
// php4 constructor
function CeoOutput($debug=0, $oid=null)
{
  $this->__construct($debug, $oid);
  register_shutdown_function( array($this, '__destruct') );
}
// END constructor

// php5 constructor
function __construct($debug=0, $oid=null)
{
  // default
  $this->debug = $debug;
  $this->oid = ( empty($oid) ) ? $this->class_name : $oid;
  $this->_set_filename();
  $this->_set_dirpath();
  
  // prepare panel array
  $this->PANEL['head'] = '';
  $this->PANEL['masthead'] = '';
  $this->PANEL['core'] = '';
  $this->PANEL['footer'] = '';
  
  // validation arrays
  $this->VALID['DOCTYPE_TYPE'] = array('html','xhtml');
  $this->VALID['DOCTYPE_VER'] = array('strict','transitional','loose','1.1');
  
  // required head elements
  $this->REQ_HEAD = array('doctype','title','description','keywords','charset');
  
  // defaults
  $this->DEFAULT['keywords'] = 'php, ceo, framework, mysql, klenwell, foo, bar';
  $this->DEFAULT['description'] = 'a heartbreaking website of staggering genius';
  
  // debug
  if ( $this->debug ) $this->print_d('debugging is active for oid ' . $this->oid);
  if ( $this->debug ) $this->print_d('constructor complete for class ' . __CLASS__);
}
// END constructor

// destructor
function __destruct()
{
  if ( $this->debug ) $this->print_d("destroying class {$this->class_name} (oid: {$this->oid})");
}
// END destructor



/* ** PUBLIC METHODS ** */
// method: print template
function print_template()
{
  $html = '';     // return

  // sanity check
  if ( empty($this->PANEL['head']) ) { trigger_error('head panel cannot be empty', E_USER_WARNING); return 0; }
  if ( empty($this->PANEL['masthead']) ) trigger_error('masthead is empty', E_USER_NOTICE);
  if ( empty($this->PANEL['core']) ) trigger_error('core is empty', E_USER_NOTICE);
  if ( empty($this->PANEL['footer']) ) trigger_error('footer is empty', E_USER_NOTICE);
  
  $html = "{$this->PANEL['head']}\n\n{$this->PANEL['masthead']}\n\n{$this->PANEL['core']}\n\n{$this->PANEL['footer']}";
  
  print $html;
}
// END method


// method: build head
function build_head()
{
  $head = '';     // return

  // required elements
  $_REQ = array('doctype', 'title');

  // sanity checks
  if ( empty($this->HEAD['doctype']) )
  {
    trigger_error('doctype is empty -- will set to default', E_USER_NOTICE); 
    $this->add_head_doctype();
  }
  if ( empty($this->HEAD['title']) )
  {
    trigger_error('title is empty -- will set to default', E_USER_NOTICE); 
    $this->add_head_title();
  }
  if ( empty($this->HEAD['description']) )
  {
    trigger_error('description is empty -- will set to default', E_USER_NOTICE); 
    $this->add_head_description();
  }
  if ( empty($this->HEAD['keywords']) )
  {
    trigger_error('keywords is empty -- will set to default', E_USER_NOTICE); 
    $this->add_head_keywords();
  }
  if ( empty($this->HEAD['charset']) )
  {
    trigger_error('charset is empty -- will set to default', E_USER_NOTICE); 
    $this->add_head_charset();
  }
  
  // unpack CSS array
  if ( !empty($this->HEAD['CSS']) )
  {
    $this->HEAD['css_list'] = '';
    foreach ( $this->HEAD['CSS'] as $_html ) $this->HEAD['css_list'] .= "  {$_html}\n";
    $this->HEAD['CSS'] = '';
  }
  
  // collect non-required elements
  $opt_head = '';
  foreach ( $this->HEAD as $_key => $_html )
  {
    if ( !in_array($_key,$this->REQ_HEAD) && !empty($_html) ) $opt_head .= "  {$_html}\n";
  }
  

  $head = <<<HTML
{$this->HEAD['doctype']}
<html>
<head>
  {$this->HEAD['title']}
  {$this->HEAD['description']}
  {$this->HEAD['keywords']}
  {$this->HEAD['charset']}
{$opt_head}   
</head>

HTML;

  return trim($head);
}
// END method


// method: add head doctype
function add_head_doctype($type='xhtml', $version='strict')
{
  if ( $this->debug ) $this->print_d("setting doctype [$type, $version]");
  
  $type = strtolower($type);
  $version = strtolower($version);
  if ( $type == 'loose' ) $type = 'transitional';   // loose = transitional

  // define valid doctypes (note: no framesets)
  $_DOC['xhtml']['strict']       = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"' . "\n" . '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
  $_DOC['xhtml']['transitional'] = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"' . "\n" . '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';
  $_DOC[ 'html']['strict']       = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"' . "\n" . '"http://www.w3.org/TR/html4/strict.dtd">';
  $_DOC[ 'html']['transitional'] = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"' . "\n" . '"http://www.w3.org/TR/html4/loose.dtd">';

  // validate
  if ( !in_array($type, $this->VALID['DOCTYPE_TYPE']) ) 
  { 
    trigger_error('invalid doctype type -- will set to xhtml');
    $type = 'xhtml';
  }
  if ( !in_array($version, $this->VALID['DOCTYPE_VER']) ) 
  { 
    trigger_error('invalid doctype version -- will set to transitional');
    $type = 'transitional';
  }
    
  $this->HEAD['doctype'] = $_DOC[$type][$version];
  return; 
}
// END method


// method: add head title
function add_head_title($title='')
{
  if ( empty($title) )
  {
    trigger_error('no title provided for head -- will set to server name');
    $title = ( !empty($_SERVER['SERVER_NAME']) ) ? $_SERVER['SERVER_NAME'] : 'A CEO Framework Project [default]';
  }
  if ( $this->debug ) $this->print_d("setting head title [$title]");
  $this->HEAD['title'] = '<title>' . $title . '</title>';
  return;
}
// END method


// method: add head keyword tag
function add_head_keywords($keywords='')
{
  if ( empty($keywords) )
  {
    trigger_error('no keywords provided for head -- will set to default');
    $keywords = $this->DEFAULT['keywords'];
  }
  if ( $this->debug ) $this->print_d("setting keywords [$keywords]");
  $this->HEAD['keywords'] = '<meta name="Keywords" content="' . $keywords . '" />';
  return;
}
// END method


// method: add head description tag
function add_head_description($description)
{
  if ( empty($description) )
  {
    trigger_error('no description provided for head -- will set to default');
    $description = $this->DEFAULT['description'];
  }
  if ( $this->debug ) $this->print_d("setting description [$description]");
  $this->HEAD['description'] = '<meta name="Description" content="' . $description . '" />';
  return;
}
// END method


// method: add head charset tag
function add_head_charset($charset='utf-8')
{
  if ( $this->debug ) $this->print_d("setting description [$charset]");
  $this->HEAD['charset'] = '<meta http-equiv="Content-Type" content="text/html; charset=' . $charset . '" />';
  return;
}
// END method


// method: add head favicon
// reference: http://en.wikipedia.org/wiki/Favicon
function add_head_favicon($href)
{
  static $num = 0;
  $num++;

  if ( $this->debug ) $this->print_d("add favicon links [$href]");
  
  if ( empty($href) )
  {
    trigger_error('no favicon href provided', E_USER_NOTICE);
    return;
  }
  
  if ( $num > 1 ) trigger_error('second favicon link -- will overwrite previous', E_USER_NOTICE);
  
  $this->HEAD['favicon'] = <<<HTML
  
<link rel="shortcut icon" href="{$href}" type="image/vnd.microsoft.icon" />
<link rel="icon" href="{$href}" type="image/vnd.microsoft.icon" />
<link rel="shortcut icon" href="{$href}" />
  
HTML;
  
  return $html;
}
// END method


// method: add external css link
function add_head_css_link($href, $top=1)
{
  /* Note
    The $top parameter places this link at the beginning of the array so that it
    will be over-ridden by all other links.  Useful for a basic stylesheet in
    default tpl file.
  */

  static $num = 0;
  $num++;
  
  if ( $this->debug ) $this->print_d("add css link [$href]");
  
  if ( empty($href) )
  {
    trigger_error('no css href provided', E_USER_NOTICE);
    return;
  }
  
  $link = '<link href="' . $href . '" type="text/css" rel="stylesheet" />';
  
  if ( empty($this->HEAD['CSS']) ) $this->HEAD['CSS'] = array();
  if ( !$top ) $this->HEAD['CSS'][] = $link;
  else array_unshift($this->HEAD['CSS'], $link);
    
  return;
}
// END method


// method: add external js link
function add_head_js_link($src)
{
  static $num = 0;
  $num++;
  
  if ( $this->debug ) $this->print_d("add js link [$src]");
  
  if ( empty($href) )
  {
    trigger_error('no js src provided', E_USER_NOTICE);
    return;
  }
  
  $this->HEAD['js'.$num] = "\n" . '<script type="text/javascript" src="' . $src .  '"></script>' . "\n";  
  return;
}
// END method


// method: add_head_internal_css
function add_head_internal_css($css_code)
{
  $html = '';   // return

  // we'll add the style tags
  $css_code = str_replace('<style type="text/css">', '', $css_code);
  $css_code = str_replace('</style>', '', $css_code);
  
  $html = <<<CSS
  
<style type="text/css">
{$css_code}
</style>
  
CSS;
  
   $this->HEAD['CSS'][] = $html;
  return;
}
// END method


// method: add_head_internal_js
function add_head_internal_js($js_code)
{
  $this->print_d(__FUNCTION__ . ' in dev');
  return;
}
// END method


// method: add_head_raw
function add_head_raw($raw)
{
  $key = md5($raw);
  $this->HEAD[$key] = $key;
  return;
}
// END method


// method: add hyperlink
function add_link($href, $label, $class='', $title='')
{
  $tag = '';
  $class = ( !empty($class) ) ? ' class="'.$class.'"' : '';
  $title = ( !empty($title) ) ? ' title="'.$title.'"' : '';
  $tag = "<a href=\"{$href}\"{$class}{$title}>{$label}</a>";
  return $tag;
}
// END method



// static: build menu list
function static_build_menu_list($MENU_ITEM, $active_item=null)
{
  $html = '';   // return

  /* NOTE
      The MENU_ITEM array should be an associate array consisting of
      label => url pairs.  $active item should be a url value, or part
      of a url value, that can be matched to an array element (and thus
      classified appropriately.
  */
  
  // type cast
  if ( !is_array($MENU_ITEM) ) $MENU_ITEM = array( $MENU_ITEM );
  
  // build list
  $_list = '';
  foreach ( $MENU_ITEM as $label => $url )
  {
    // tidy labels
		$label = str_replace('_', ' ', $label);
		
		// check for active url
		$is_active = ( strpos($url, $active_item) !== FALSE ) ? 1 : 0;
		
		// active url?
		if ( $is_active )
		{
			$_list .= "<li><a class=\"active\" href=\"{$url}\">{$label}</a></li>\n";
		}
		else
		{
			$_list .= "<li><a href=\"{$url}\">{$label}</a></li>\n";
		}
  }
  
  // wrap list
  $html = ( !empty($_list) ) ? "<ul class=\"menu_list\">\n$_list</ul>" : '';

  return $html;
}
// END method



// method: print_d
function print_d($message, $color='#c33')
{
  $out = "<div style='line-height:1.5em; font-family:monospace; color:$color;'>$message</div>";
  echo $out;
  return;
}
// END method

// method: print_r
function print_r($Mixed)
{
  $return = htmlspecialchars(print_r($Mixed, 1));
  $return = "<pre>$return</pre>";
  return $return;
}
// END method

// method: dump
function dump()
{
  echo $this->print_r($this);
  return;
}
// END method



/* ** PRIVATE METHODS ** */
// method: _set_session_data
function _set_session_data()
{
  // initialize session
  if ( !session_id() ) session_start(); 
  $_SESSION[$this->oid] = array();
  
  // add session data here
  
  return;
}
// END method

// method: get session data
function _get_session_data()
{
  // initialize session
  if ( !$this->_has_session_data() ) return; 
    
  // retrieve session variables
  // $this->var = $_SESSION[$this->oid]['var'];
  
  return;
}
// END method

// method: has session data
function _has_session_data()
{
  // initialize session
  if ( !session_id() ) session_start(); 
    
  // retrieve session variables
  if ( empty($_SESSION[$this->oid]) ) return 0;
  else return 1;
}
// END method

function _set_filename() { $this->_filename = basename(__FILE__); }
function _set_dirpath() { $this->_dirpath = dirname(__FILE__) . $this->DS; }

} // end class
/*____________________________________________________________________________*/

?>
